package ink.xiaobaibai.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ink.xiaobaibai.dao.CouponCodeDao;
import ink.xiaobaibai.entity.CouponCode;
import ink.xiaobaibai.entity.CouponCodeLog;
import ink.xiaobaibai.service.ICouponCodeLogService;
import ink.xiaobaibai.service.ICouponCodeService;
import ink.xiaobaibai.serviceOxy.IRedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xiaobaibai
 * @since 2021-08-06
 */
@Service
public class CouponCodeServiceImpl extends ServiceImpl<CouponCodeDao, CouponCode> implements ICouponCodeService {

    private static final String PRE = "code_pre:";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private IRedisUtils redisUtils;

    @Autowired
    private ICouponCodeLogService couponCodeLogService;

    @Override
    public void addCouponCodeBitMap(String letterPre, Date expiresTime) {
        this.stringRedisTemplate.opsForValue().setBit(PRE + letterPre, 0, true);
        long seconds = (expiresTime.getTime() - System.currentTimeMillis()) / 1000;
        this.stringRedisTemplate.expire(PRE + letterPre, seconds, TimeUnit.SECONDS);
    }

    @Override
    public void updateCouponBitMap(String letterPre, Date expiresTime) {
        long seconds = (expiresTime.getTime() - System.currentTimeMillis()) / 1000;
        this.stringRedisTemplate.expire(PRE + letterPre, seconds, TimeUnit.SECONDS);
    }

    @Override
    public CouponCode validCouponCode(String code, Integer type) {
        String letterPre = code.substring(0, 6);
        QueryWrapper<CouponCode> q1 = new QueryWrapper<>();
        q1.select("expires_time", "count", "type", "percentage");
        q1.eq("letter_pre", letterPre);
        CouponCode couponCode = this.getOne(q1);
        if (type != null && !type.equals(couponCode.getType())) {
            return null;
        }
        if (couponCode.getExpiresTime().getTime() < System.currentTimeMillis()) {
            return null;
        }
        String key = PRE + letterPre;
        Integer count = Integer.parseInt(code.substring(6));
        if (count <= 0 || count > couponCode.getCount()) {
            return null;
        }
        // false为未使用
        if (this.stringRedisTemplate.hasKey(key) && !this.stringRedisTemplate.opsForValue().getBit(key, count)) {
            return couponCode;
        }
        return null;
    }

    @Override
    public void useCouponCode(String code) {
        String letterPre = code.substring(0, 6);
        String key = PRE + letterPre;
        Integer count = Integer.parseInt(code.substring(6));
        this.stringRedisTemplate.opsForValue().setBit(key, count, true);
    }

    @Override
    public Integer getCouponPercentage(String code) {
        String letterPre = code.substring(0, 6);
        QueryWrapper<CouponCode> q1 = new QueryWrapper<>();
        q1.select("percentage");
        q1.eq("letter_pre", letterPre);
        return this.getOne(q1).getPercentage();
    }

    @Override
    public void unlockCouponCode(String code) {
        String letterPre = code.substring(0, 6);
        String key = PRE + letterPre;
        Integer count = Integer.parseInt(code.substring(6));
        this.stringRedisTemplate.opsForValue().setBit(key, count, false);
    }

    @Override
    public void deleteCouponBit(String letterPre) {
        this.stringRedisTemplate.delete(PRE + letterPre);
    }

    @Override
    public void consumeCouponCode(String orderId, Integer userId) {
        String couponCode = this.redisUtils.getCouponCode(orderId);
        if (couponCode != null) {
            // 消耗这个券
            CouponCodeLog couponCodeLog = new CouponCodeLog(couponCode, orderId);
            this.couponCodeLogService.save(couponCodeLog);
            // 优惠码变成已经使用
            this.useCouponCode(couponCode);
        }
    }
}
